#ifndef __String_hpp__
#define __String_hpp__

#include "Utils.hpp"

namespace ge {

//----------------------------------------------------------------------------//
// String 
//----------------------------------------------------------------------------//

class String
{
 public:

     class Buffer
     {

      friend class String;

      public:

          Buffer( void );

          Buffer( const char* _str, uint _offset = 0, int _length = -1, int _reserve = -1, bool _valid_params = false );

          Buffer* Clone( uint _offset = 0, int _length = -1, int _reserve = -1, bool _valid_params = false ) const;

          Buffer* Exchange( const Buffer* _buffer );

          Buffer* OnModify( int _reserve = -1 );

          Buffer* OnAppend( uint _append );

          Buffer* AddRef( void ) const;

          Buffer* Release( void );

          char* Data( void )
          {
               return data;
          }

          const char* Data( void ) const
          {
               return data;
          }

          uint Length( void ) const
          {
               return length;
          }

          uint Size( void ) const
          {
               return size;
          }

      public:

          char* data;
          uint length;

      protected:

          ~Buffer( void );

          uint size;
          mutable int refcnt;

      private:

          Buffer( const Buffer& );
          Buffer& operator = ( const Buffer& );

          static Buffer* _GetDefaultBuffer( void ); // for String
          static Buffer* _FromChar( char _ch ); // for String
     };

 public:

     String( void );

     ~String( void );

     String( int );

     String( char _ch );

     String( const char* _str );

     String( const char* _str, uint _offset, int _length = -1 );

     String( const String& _str );

     String( const String& _str, uint _offset, int _length = -1 );

     String( const Buffer* _buffer );

     char operator [] ( uint _index ) const
     {
          return geChoose( _index < m_buffer -> length, m_buffer -> data[_index], 0 );
     }

     char operator [] ( int _index ) const
     {
          return geChoose( _index >= 0 && (uint)_index < m_buffer -> length, m_buffer -> data[_index], 0 );
     }

     operator const char* ( void ) const
     {
          return m_buffer -> data;
     }

     String& operator = ( const String& _str )
     {
          m_buffer = m_buffer -> Exchange( _str.m_buffer );
          return *this;
     }

     String& operator = ( const char* _str )
     {
          Buffer* _old = m_buffer;
          m_buffer = new Buffer( _str );
          _old -> Release();
          return *this;
     }

     String& operator = ( char _ch )
     {
          char _str[] = { _ch, 0 };
          return *this = _str;
     }

     String operator + ( const String& _str ) const
     {
          return String( *this ).Append( _str );
     }

     String operator + ( const char* _str ) const
     {
          return String( *this ).Append( _str );
     }

     String operator + ( char _ch ) const
     {
          return String( *this ).Append( _ch );
     }

     String& operator += ( const String& _str )
     {
          return Append( _str );
     }

     String& operator += ( const char* _str )
     {
          return Append( _str );
     }

     String& operator += ( char _ch )
     {
          return Append( _ch );
     }

     friend String operator + ( const char* _str, const String& _r )
     {
          return String( _str ).Append( _r );
     }

     friend String operator + ( char _ch, const String& _r )
     {
          return String( _ch ).Append( _r );
     }

     String operator / ( const String& _str ) const
     {
          return String( *this ).Append( '/' ).Append( _str );
     }

     String operator / ( const char* _str ) const
     {
          return String( *this ).Append( '/' ).Append( _str );
     }

     String operator / ( char _ch ) const
     {
          return String( *this ).Append( '/' ).Append( _ch );
     }

     String& operator /= ( const String& _str )
     {
          return Append( '/' ).Append( _str );
     }

     String& operator /= ( const char* _str )
     {
          return Append( '/' ).Append( _str );
     }

     String& operator /= ( char _ch )
     {
          return Append( '/' ).Append( _ch );
     }

     friend String operator / ( const char* _str, const String& _r )
     {
          return String( _str ).Append( '/' ).Append( _r );
     }

     friend String operator / ( char _ch, const String& _r )
     {
          return String( _ch ).Append( '/' ).Append( _r );
     }

     String& Append( char _ch );

     String& Append( char _ch, uint _count );

     String& Append( const char* _str, uint _offset = 0, int _length = -1 );

     uint Length( void ) const
     {
          return m_buffer -> length;
     }

     const char* Data( void ) const
     {
          return m_buffer -> data;
     }

     char* EditData( void )
     {
          return ( m_buffer = m_buffer -> OnModify() ) -> data;
     }

     void EndEdit( void )
     {
          m_buffer -> length = Length( m_buffer -> data );
     }

     String& Reserve( uint _reserve )
     {
          m_buffer = m_buffer -> OnModify( Length() + _reserve );
          return *this;
     }

     void Swap( String& _str )
     {
          ge::Swap( m_buffer, _str.m_buffer );
     }

     bool operator == ( const String& _str ) const
     {
          return m_buffer == _str.m_buffer || ( Length() == _str.Length() && Compare( Data(), _str.Data() ) == 0 );
     }

     bool operator == ( const char* _str ) const
     {
          return Compare( Data(), _str ) == 0;
     }

     bool operator != ( const String& _str ) const
     {
          return !(*this == _str);
     }

     bool operator != ( const char* _str ) const
     {
          return !(*this == _str);
     }

     bool operator < ( const String& _str ) const
     {
          return Compare( Data(), _str.Data() ) < 0; 
     }

     bool operator < ( const char* _str ) const
     {
          return Compare( Data(), _str ) < 0; 
     }

     bool operator <= ( const String& _str ) const
     {
          return Compare( Data(), _str.Data() ) <= 0; 
     }

     bool operator <= ( const char* _str ) const
     {
          return Compare( Data(), _str ) <= 0; 
     }

     bool operator > ( const String& _str ) const
     {
          return Compare( Data(), _str.Data() ) > 0; 
     }

     bool operator > ( const char* _str ) const
     {
          return Compare( Data(), _str ) > 0; 
     }

     bool operator >= ( const String& _str ) const
     {
          return Compare( Data(), _str.Data() ) >= 0; 
     }

     bool operator >= ( const char* _str ) const
     {
          return Compare( Data(), _str ) >= 0; 
     }

     int CompareIgnoreCase( const char* _str ) const
     {
          return CompareIgnoreCase( Data(), _str );
     }

     bool EqualIgnoreCase( const char* _str ) const
     {
          return CompareIgnoreCase( _str ) == 0;
     }

     bool IsEmpty( void ) const
     {
          return m_buffer -> length == 0;
     }

     bool NonEmpty( void ) const
     {
          return m_buffer -> length != 0;
     }

     const char* Search( const char* _str ) const
     {
          return Search( Data(), _str );
     }

     const char* Search( char _ch ) const
     {
          return Search( Data(), _ch );
     }

     const char* SearchFirst( const char* _str ) const
     {
          return Search( Data(), _str );
     }

     const char* SearchFirst( char _ch ) const
     {
          return Search( Data(), _ch );
     }

     const char* SetachNext( const char* _start, const char* _str ) const
     {
          return Search( _start, _str );
     }

     const char* SetachNext( const char* _start, char _ch ) const
     {
          return Search( Data(), _ch );
     }

     const char* SearchLast( const char* _str ) const
     {
          return SearchLast( Data(), _str );
     }

     const char* SearchLast( char _ch ) const
     {
          return Search( Data(), _ch );
     }

     String SubString( uint _offset, int _length = -1 ) const
     {
          return m_buffer -> Clone( _offset, _length ); 
     }

     void Clear( void )
     {
          m_buffer = m_buffer -> OnModify();
          m_buffer -> data[0] = 0;
          m_buffer -> length = 0;
     }

     // ToLower();
     // ToUpper();

     bool ToBool( bool _default = false ) const
     {
          return ToBool( *this, _default );
     }

     int ToInt( int _default = 0 ) const
     {
          return ToInt( *this, _default );
     }

     float ToFloat( float _default = 0.0f ) const
     {
          return ToFloat( *this, _default );
     }

 public:

     // Utils
     enum
     {
          IgnoreCase = true,
          NoIgnoreCase = false,
     };

     struct LessIgnoreCase
     {
          bool Eq( const String& _a, const String& _b ) const
          {
               return Cmp( _a, _b, IgnoreCase ) == 0;
          }

          bool Lt( const String& _a, const String& _b ) const
          {
               return Cmp( _a, _b, IgnoreCase ) < 0;
          }

          bool Le( const String& _a, const String& _b ) const
          {
               return Cmp( _a, _b, IgnoreCase ) <= 0;
          }
     };

     struct GreaterIgnoreCase
     {
          bool Eq( const String& _a, const String& _b ) const
          {
               return Cmp( _a, _b, IgnoreCase ) == 0;
          }

          bool Lt( const String& _a, const String& _b ) const
          {
               return Cmp( _a, _b, IgnoreCase ) >= 0;
          }

          bool Le( const String& _a, const String& _b ) const
          {
               return Cmp( _a, _b, IgnoreCase ) > 0;
          }
     };

     static uint Length( const char* _str );

     static int Compare( const char* _a, const char* _b );

     static int CompareIgnoreCase( const char* _a, const char* _b );

     static int Cmp( const char* _a, const char* _b, bool _ignore_case = false )
     {
          return geChoose( _ignore_case, Compare( _a, _b ), CompareIgnoreCase( _a, _b ) );
     }

     static String FormatVL( const char* _fmt, va_list _args );

     static String Format( const char* _fmt, ... );

     static char* SizeAsString( char* _buffer, uint _max_length, uint _value );

     static String SizeAsString( uint _value );

     static const char* Search( const char* _src, const char* _str );

     static const char* Search( const char* _src, char _ch );

     static const char* SearchLast( const char* _src, const char* _str );

     static const char* SearchLast( const char* _src, char _ch );

     static char* Search( char* _src, const char* _str );

     static char* Search( char* _src, char _ch );

     static char* SearchLast( char* _src, const char* _str );

     static char* SearchLast( char* _src, char _ch );

     static bool ToBool( const char* _value, bool _default = false );

     static int ToInt( const char* _value, int _default = 0 );

     static float ToFloat( const char* _value, float _default = 0.0f );

     static String Bool( bool _value, bool _as_string = true, bool _true_false = false )
     {
          if( _as_string ) return geChoose( _true_false, geChoose( _value, "true", "false" ),  geChoose( _value, "yes", "no" ) );
          return geChoose( _value, "1", "0" );
     }

     static String Int( int _value, bool _as_hexadecimal = false )
     {
          return Format( geChoose( _as_hexadecimal, "0x%04x", "%d" ), _value );
     }

     static String Float( float _value, int _precision = 3 )
     {
          if( _precision < 0 ) _precision = 0;
          if( _precision > 9 ) _precision = 9;
          char _format[] = { '%', '.', '0' + _precision, 'f', 0 };
          return Format( _format, _value );
     }

 protected:

     Buffer* m_buffer;
};

#define geFormat( _msg, ... ) ge::String::Format( _msg, __VA_ARGS__ )

typedef Array< String > StringArray;
typedef List< String > StringList;

inline void Swap( String& _a, String& _b )
{
     _a.Swap( _b );
}

} // namespace ge

#endif//__String_hpp__
